﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Controls.Maps;
using System.Device.Location;
using Microsoft.Phone.Tasks;
using System.Text;
using System.IO;
using System.Xml.Linq;
using System.Runtime.Serialization.Json;
using System.Collections.ObjectModel;
using Newtonsoft.Json;
using ScottIsAFool.Controls;


namespace unifiqAnthony
{
    public partial class FriendsLocationPage : PhoneApplicationPage
    {

        GeoCoordinateWatcher watcher;
        internal const string id = "Aggp0yd8miqzaqQrXChtjs8v2m4nlHd3lFn06-W9gu7ZI4KBhTzUddWbVjayXfTV"; //Bing key
        double currentLat = 0;
        double currentLong = 0;
        Boolean bShow = false;
        MapLayer pinLayer = new MapLayer();
        MapLayer FriendLayer = new MapLayer();
        MapLayer GirlLayer = new MapLayer();
        Friend[] FriendLocations = new Friend[21];

        List<FriendDistance> FriendDistance = new List<FriendDistance>();

        private string uid, lat, longit;

        public FriendsLocationPage()
        {
            InitializeComponent();

            //boy
            FriendLocations[1] = new Friend("9 , Bishan Place , #B1-01, Junction 8 Shopping Centre ,SINGAPORE 579837", 1.350529, 103.848437);
            FriendLocations[2] = new Friend("201 Henderson Road", 1.283619, 103.820561);
            
            //girl
            FriendLocations[8] = new Friend("Blk 468B Admiralty Drive #01-29 S(752468)", 1.450182, 103.81415);
            FriendLocations[9] = new Friend("LT2A NTU, Singapore", 1.364236, 103.684051);
            
            //add the markers on the map
            AddPushpinsOnMap();
            bShow = false;

            if (watcher == null)
            {
                watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.Default);
                watcher.MovementThreshold = 20;
                watcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged); //event occurs when position change
            }
            watcher.Start();
        }

        void updateLoc(string lat, string longit)
        {

            var url = "http://unifiq.5kportal.com/debbiewindows/update_location.php";

            this.lat = lat; this.longit = longit;

            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
            webRequest.Method = "POST";
            webRequest.ContentType = "application/x-www-form-urlencoded";

            webRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), webRequest);
            MessageBox.Show("LocationUpdated!");
        }

        void GetRequestStreamCallback(IAsyncResult asynchronousResult)
        {
            HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
            // End the stream request operation
            Stream postStream = webRequest.EndGetRequestStream(asynchronousResult);

            string postData = "uid=1&lat=" + lat + "&longit=" + longit;

            byte[] byteArray = Encoding.UTF8.GetBytes(postData);

            // Add the post data to the web request
            postStream.Write(byteArray, 0, byteArray.Length);
            postStream.Close();

            // Start the web request
            webRequest.BeginGetResponse(new AsyncCallback(GetResponseCallback), webRequest);
        }
        void GetResponseCallback(IAsyncResult asynchronousResult)
        {

            try
            {
                HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
                HttpWebResponse response;

                // End the get response operation
                response = (HttpWebResponse)webRequest.EndGetResponse(asynchronousResult);
                Stream streamResponse = response.GetResponseStream();
                StreamReader streamReader = new StreamReader(streamResponse);
                var Response = streamReader.ReadToEnd();
                streamResponse.Close();
                streamReader.Close();
                response.Close();

            }
            catch (WebException e)
            {
                MessageBox.Show(e.ToString());
            }
        }
        
        private readonly CredentialsProvider _credentialsProvider = new ApplicationIdCredentialsProvider(id);

        public CredentialsProvider CredentialsProvider
        {
            get { return _credentialsProvider; }
        }

        void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            //when coordinates are found, get the current location coordinate centered on the map
            this.Map.Center = new GeoCoordinate(e.Position.Location.Latitude, e.Position.Location.Longitude);

            // bug fix for Microsoft's location service default location
            if (e.Position.Location.Latitude == 47.64483)
            {
                this.Map.Center = new GeoCoordinate(1.358751, 103.844624);
            }
            if (this.Map.Children.Count != 0)
            {
                var pushpin = Map.Children.FirstOrDefault(p => (p.GetType() == typeof(Pushpin)));
                if (pushpin != null)
                {
                    this.Map.Children.Remove(pushpin);
                }
            }

            //initialise pushpin object, retrieve current location coordinates and set it on the map

            Pushpin locationPushpin = new Pushpin();
            locationPushpin.Tag = "CurrentLocation";
            locationPushpin.Template = this.Resources["ImagePin"] as ControlTemplate; //Control template for pushpin
            
            //current location happen to be at Microsoft's location, fix it to the Center initialised (Singapore's coordinate)
            if (e.Position.Location.Latitude == 47.64483)
            {
                locationPushpin.Location = this.Map.Center;
                currentLat = this.Map.Center.Latitude;
                currentLong = this.Map.Center.Longitude;
                updateLoc(currentLat.ToString(), currentLong.ToString());
                this.Map.Children.Add(locationPushpin);
                this.Map.SetView(this.Map.Center, 10.5);
            } //end of bug fix

            else
            {
                locationPushpin.Location = watcher.Position.Location;
                currentLat = watcher.Position.Location.Latitude;
                currentLong = watcher.Position.Location.Longitude;
                updateLoc(currentLat.ToString(), currentLong.ToString());
                this.Map.Children.Add(locationPushpin);
                this.Map.SetView(watcher.Position.Location, 15.0);
            }
        }

        private void AddPushpinsOnMap()
        {
            int i = 0;
            foreach (Friend c in FriendLocations)
            {//boy

                if (i < 3)
                {
                    Pushpin locationPushpin = new Pushpin();
                    locationPushpin.Tag = "BoyLocation";
                    if (c != null)
                    {
                        GeoCoordinate FriendLatLong = new GeoCoordinate(c.lat, c.longt);
                        locationPushpin.Location = FriendLatLong;
                        locationPushpin.Template = this.Resources["ImagePin2"] as ControlTemplate;
                        FriendLayer.Children.Add(locationPushpin);
                        
                    }
                }
                //girl
                if (i >= 3 && i < 13)
                {
                    Pushpin locationPushpin = new Pushpin();
                    locationPushpin.Tag = "GirlLocation";
                    if (c != null)
                    {
                        GeoCoordinate FriendLatLong = new GeoCoordinate(c.lat, c.longt);
                        locationPushpin.Location = FriendLatLong;
                        locationPushpin.Template = this.Resources["ImagePin3"] as ControlTemplate;
                        GirlLayer.Children.Add(locationPushpin);
                    }
                }
                i++;
            }
        }

        private void AppBarShowAll_Click(object sender, EventArgs e)
        {
            //show all Friend
            if (bShow == false)
            {
                this.Map.Children.Add(FriendLayer);
                this.Map.Children.Add(GirlLayer);
                bShow = true;
            }
            else
            {
                this.Map.Children.Remove(FriendLayer);
                this.Map.Children.Remove(GirlLayer);
                bShow = false;
            }
        }

        private void AppBarNTUC_Click(object sender, EventArgs e)
        {
            //show NTUC
            if (bShow == false)
            {
                this.Map.Children.Add(FriendLayer);
                bShow = true;
            }
            else
            {
                this.Map.Children.Remove(FriendLayer);
                bShow = false;
            }
        }

        private void AppBarShopNSave_Click(object sender, EventArgs e)
        {
            //show Shop NSave
            if (bShow == false)
            {
                this.Map.Children.Add(GirlLayer);
                bShow = true;
            }
            else
            {
                this.Map.Children.Remove(GirlLayer);
                bShow = false;
            }
        }

        private void AppBarShowNearest_Click(object sender, EventArgs e)
        {//show nearest Friend
            /*
            foreach (Friend FriendLocation in FriendLocations)
            {
                if (FriendLocation != null)
                {
                    if (currentLat != 0 && currentLong != 0)
                    {
                        FriendDistance.Add(new FriendDistance(FriendLocation.name, FriendLocation.lat, FriendLocation.longt, GetDistanceBetweenPoints(currentLat, currentLong, FriendLocation)));
                    }
                }
            }
            //sort the distance calculated between current and nearest clinis location, arrange from ascending
            List<FriendDistance> sortedList = FriendDistance.OrderBy(cl => cl.DistanceFromCurrentLocation1).ToList();
            MessageBoxResult m = MessageBox.Show(sortedList[0].name, "To Route to this supermarket", MessageBoxButton.OKCancel); //and then display info of the nearest Friend
            if (m == MessageBoxResult.OK)
            {
                RouteTo();
            }*/
        }

        //method to calculate distance between current location and each friend
        public double GetDistanceBetweenPoints(double currentLat, double currentLong, Friend friendLocation)
        {
            double lat2 = friendLocation.lat;
            double long2 = friendLocation.longt;
            double distance = 0;
            double dLat = (lat2 - currentLat) / 180 * Math.PI;
            double dLong = (long2 - currentLong) / 180 * Math.PI;
            double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2)
            + Math.Cos(lat2) * Math.Sin(dLong / 2) * Math.Sin(dLong / 2);
            double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
            //Calculate radius of earth
            // assume any of the two points.
            double radiusE = 6378135; // Equatorial radius, in metres
            double radiusP = 6356750; // Polar Radius
            //Numerator part of function
            double nr = Math.Pow(radiusE * radiusP * Math.Cos(currentLat / 180 * Math.PI), 2);
            //Denominator part of the function
            double dr = Math.Pow(radiusE * Math.Cos(currentLat / 180 * Math.PI), 2)
            + Math.Pow(radiusP * Math.Sin(currentLat / 180 * Math.PI), 2);
            double radius = Math.Sqrt(nr / dr);
            //Calaculate distance in metres.
            distance = radius * c;
            return distance;
        }

        private void RouteTo()
        {
            //route to the nearest Friend from current position
            foreach (Friend FriendLocation in FriendLocations)
            {
                if (FriendLocation != null)
                {
                    if (currentLat != 0 && currentLong != 0)
                    {
                        FriendDistance.Add(new FriendDistance(FriendLocation.name, FriendLocation.lat, FriendLocation.longt, GetDistanceBetweenPoints(currentLat, currentLong, FriendLocation)));
                    }
                }
            }

            //sort the distance calculated between current and nearest Friend location, arrange from ascending
            //get shortest route to find nearest Friend coordinate
            List<FriendDistance> sortedList = FriendDistance.OrderBy(cl => cl.DistanceFromCurrentLocation1).ToList();
            //and pass coordinates of nearestFriend and current location to BingMapsDirectionTask to provide direction
            BingMapsDirectionsTask getDirection = new BingMapsDirectionsTask();

            getDirection.Start = new LabeledMapLocation("Current Location", new GeoCoordinate(currentLat, currentLong));
            getDirection.End = new LabeledMapLocation(sortedList[0].name, new GeoCoordinate(sortedList[0].lat, sortedList[0].longt));
            //sortedList[0] is the 1st item in arraylist, with the shortest distance from currentlocation
            //show directions
            getDirection.Show();
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {

            AzureSvc.Service1Client client = new AzureSvc.Service1Client();
            client.getUUserAsync(1);
            client.getUUserCompleted += new EventHandler<AzureSvc.getUUserCompletedEventArgs>(client_getUUserCompleted);

        }


        private void client_getUUserCompleted(object sender, AzureSvc.getUUserCompletedEventArgs e)
        {
            //result
            textBlock1.Text = e.Result.userEmail.ToString();
        }

}
}